return {
  "saghen/blink.cmp",
  enabled = true,
  version = not vim.g.lazyvim_blink_main and "*",
  build = vim.g.lazyvim_blink_main and "cargo build --release",
  opts_extend = {
    "sources.completion.enabled_providers",
    "sources.compat",
    "sources.default",
  },
  dependencies = {
    "moyiz/blink-emoji.nvim",
    "Kaiser-Yang/blink-cmp-dictionary",
    "rafamadriz/friendly-snippets",
    -- add blink.compat to dependencies
    {
      "saghen/blink.compat",
      optional = true, -- make optional so it's only enabled if any extras need it
      opts = {},
      version = not vim.g.lazyvim_blink_main and "*",
    },
  },
  event = "InsertEnter",

  ---@module 'blink.cmp'
  ---@type blink.cmp.Config
  opts = {
    snippets = {
      expand = function(snippet)
        return LazyVim.cmp.expand(snippet)
      end,
    },
    appearance = {
      -- sets the fallback highlight groups to nvim-cmp's highlight groups
      -- useful for when your theme doesn't support blink.cmp
      -- will be removed in a future release, assuming themes add support
      use_nvim_cmp_as_default = false,
      -- integrations = { blink_cmp = true },
      -- set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font'
      -- adjusts spacing to ensure icons are aligned
      nerd_font_variant = "mono",
    },
    completion = {
      accept = {
        -- experimental auto-brackets support
        auto_brackets = {
          enabled = true,
        },
      },
      menu = {
        draw = {
          treesitter = { "lsp" },
        },
      },
      documentation = {
        auto_show = true,
        auto_show_delay_ms = 200,
      },
      ghost_text = {
        enabled = vim.g.ai_cmp,
      },
    },

    -- experimental signature help support
    signature = { enabled = true },

    sources = {
      -- adding any nvim-cmp sources here will enable them
      -- with blink.compat
      compat = {},
      -- default = { "lsp", "path", "snippets", "buffer", "dadbod", "emoji", "dictionary" },
      default = { "lsp", "path", "snippets", "buffer", "dadbod" },
      per_filetype = {
        sql = { "snippets", "dadbod", "buffer" },
      },
      providers = {
        buffer = {
          name = "Buffer",
          enabled = true,
          max_items = 3,
          module = "blink.cmp.sources.buffer",
          min_keyword_length = 2,
          score_offset = 20,
        },
        path = {
          name = "Path",
          module = "blink.cmp.sources.path",
          score_offset = 30,
        },
        snippets = {
          name = "snippets",
          enabled = true,
          module = "blink.cmp.sources.snippets",
          score_offset = 10,
        },
        lsp = {
          name = "lsp",
          enabled = true,
          -- module = "blink.cmp.sources.lsp",
          kind = "LSP",
          -- min_keyword_length = 2,
          score_offset = 100,
        },
        dadbod = {
          name = "Dadbod",
          module = "vim_dadbod_completion.blink",
          -- min_keyword_length = 2,
          score_offset = 95,
        },
      },
    },

    cmdline = {
      enabled = true, -- 控制cmdline 补全
      -- completion = {
      --   ghost_text = { enabled = true },
      -- },
    },
    --TODO: 1.<S-k> 显示方法提示文档后 不会关闭
    --TODO: 2.cmp usePlaceholder占位符关闭后 不会开启
    keymap = {
      preset = "enter",
      -- preset = "none",
      ["<C-y>"] = { "select_and_accept" },
      ["<C-space>"] = {
        function(cmp)
          cmp.show()
        end,
      },
      ["<CR>"] = {
        -- Edit by yueking this's my favorite
        function(cmp)
          -- vim.notify("A")
          -- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<CR>", true, false, true), "n", false)
          -- vim.notify(cmp.is_active(), cmp.is_visible(), cmp.snippet_active())
          -- 3114
          if cmp.is_visible() and cmp.snippet_active() then
            vim.notify("1")
            -- TODO:🤓需要判断  不是对象 不是方法 或无返回值的方法 或仅为简单类型时进行 cmp.snippet_forward 操作
            -- return cmp.select_and_accept() and cmp.snippet_forward()
            return cmp.select_and_accept()
          elseif not cmp.is_visible() and cmp.snippet_active() then
            vim.notify("2")
            return cmp.snippet_forward()
          elseif cmp.is_visible() and not cmp.snippet_active() then
            vim.notify("3")
            return cmp.select_and_accept()
          elseif not cmp.is_visible() and not cmp.snippet_active() then
            vim.notify("4")
          elseif cmp.is_visible() and cmp.snippet_active({ direction = -1 }) then
            vim.notify("5")
          elseif not cmp.is_visible() and cmp.snippet_active({ direction = -1 }) then
            vim.notify("6")
          elseif cmp.is_visible() and not cmp.snippet_active({ direction = -1 }) then
            vim.notify("7")
          elseif not cmp.is_visible() and not cmp.snippet_active({ direction = -1 }) then
            vim.notify("8")
          elseif not cmp.is_visible() and cmp.snippet_active({ direction = 1 }) then
            vim.notify("9")
          elseif not cmp.is_visible() and not cmp.snippet_active({ direction = 1 }) then
            vim.notify("10")
          elseif cmp.is_visible() and cmp.snippet_active({ direction = 1 }) then
            vim.notify("11")
          elseif cmp.is_visible() and not cmp.snippet_active({ direction = 1 }) then
            vim.notify("12")
          else
            vim.notify("13")
          end
          -- 2113

          local a = cmp.is_active()
          local v = cmp.is_visible()
          local s = cmp.snippet_active()
          local e = cmp.snippet_active({ direction = -1 })

          local status = tostring(a) .. tostring(v) .. tostring(s) .. tostring(e)
          -- vim.notify(status)

          if a and v and not s then
            return cmp.select_and_accept()
          end

          if a and v and s then
            return cmp.select_and_accept() and cmp.snippet_forward()
          end

          if a and not v and s and e then
            return cmp.snippet_forward()
          end

          if a and not v and not s and not e then
            vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<CR>", true, false, true), "n", false)
            return false
          end

          -- if cmp.snippet_active() and cmp.is_active() and not cmp.is_visible() then
          --   vim.notify("1")
          --   return cmp.snippet_forward()
          -- end

          -- if cmp.snippet_active({ direction = -1 }) then
          --   vim.notify("0")
          --   return cmp.select_accept_and_enter()
          -- end

          -- vim.notify("B")

          -- if cmp.is_visible() then
          --   if cmp.snippet_active() then
          --     vim.notify("2")
          --     return cmp.select_and_accept() and cmp.snippet_forward()
          --   else
          --     vim.notify("3")
          --     return cmp.select_and_accept()
          --   end
          -- else
          --   if cmp.snippet_active() then
          --     vim.notify("4")
          --     return cmp.snippet_forward()
          --   elseif cmp.is_visible() and not cmp.snippet_active() then
          --     vim.notify("5")
          --     return cmp.select_and_accept()
          --   else
          --     vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<CR>", true, false, true), "n", false)
          --     vim.notify("6")
          --     return false
          --   end
          -- end
        end,
      },
    },
  },
  ---@param opts blink.cmp.Config | { sources: { compat: string[] } }
  config = function(_, opts)
    -- setup compat sources
    local enabled = opts.sources.default
    for _, source in ipairs(opts.sources.compat or {}) do
      opts.sources.providers[source] = vim.tbl_deep_extend(
        "force",
        { name = source, module = "blink.compat.source" },
        opts.sources.providers[source] or {}
      )
      if type(enabled) == "table" and not vim.tbl_contains(enabled, source) then
        table.insert(enabled, source)
      end
    end

    -- add ai_accept to <Tab> key
    if not opts.keymap["<Tab>"] then
      if opts.keymap.preset == "super-tab" then -- super-tab
        opts.keymap["<Tab>"] = {
          require("blink.cmp.keymap.presets")["super-tab"]["<Tab>"][1],
          LazyVim.cmp.map({ "snippet_forward", "ai_accept" }),
          "fallback",
        }
      else -- other presets
        opts.keymap["<Tab>"] = {
          LazyVim.cmp.map({ "snippet_forward", "ai_accept" }),
          "fallback",
        }
      end
    end

    -- Unset custom prop to pass blink.cmp validation
    opts.sources.compat = nil

    -- check if we need to override symbol kinds
    for _, provider in pairs(opts.sources.providers or {}) do
      ---@cast provider blink.cmp.SourceProviderConfig|{kind?:string}
      if provider.kind then
        local CompletionItemKind = require("blink.cmp.types").CompletionItemKind
        local kind_idx = #CompletionItemKind + 1

        CompletionItemKind[kind_idx] = provider.kind
        ---@diagnostic disable-next-line: no-unknown
        CompletionItemKind[provider.kind] = kind_idx

        ---@type fun(ctx: blink.cmp.Context, items: blink.cmp.CompletionItem[]): blink.cmp.CompletionItem[]
        local transform_items = provider.transform_items
        ---@param ctx blink.cmp.Context
        ---@param items blink.cmp.CompletionItem[]
        provider.transform_items = function(ctx, items)
          items = transform_items and transform_items(ctx, items) or items
          for _, item in ipairs(items) do
            item.kind = kind_idx or item.kind
            item.kind_icon = LazyVim.config.icons.kinds[item.kind_name] or item.kind_icon or nil
          end
          return items
        end

        -- Unset custom prop to pass blink.cmp validation
        provider.kind = nil
      end
    end

    require("blink.cmp").setup(opts)
    -- require("render-markdown").setup({
    --   completions = {
    --     blink = { enabled = true },
    --   },
    -- })
  end,
}
